package com.example.jackhsueh.ble_ota;

import android.app.Activity;
import android.bluetooth.BluetoothGatt;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import com.blankj.utilcode.util.ConvertUtils;
import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleGattCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleReadCallback;
import com.clj.fastble.callback.BleScanCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.hjq.permissions.OnPermission;
import com.hjq.permissions.XXPermissions;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class V30TestActivity extends Activity {
    private ListView listView;
    private EditText etLog;
    private SimpleAdapter myBleDeviceAdapter;
    List<Map<String, String>> deviceList = new ArrayList<Map<String, String>>();
    private List<BleDevice> resultBle;
    final int MAX_TRANS_COUNT_V30 = 20; //每包大小
    final int MAX_TRANS_SECTIONALL_COUNT = 5120;//每段大小
    final int MAX_TRANS_SECTIONALL_PACKET_COUNT = MAX_TRANS_SECTIONALL_COUNT / 20;//每段的包数
    private int MAX_TRANS_SECTIONALL_SIZE = 0;//当前段的大小
    private int MAX_TRANS_COUNT = 0;//总段数
    private String OTA_FilePath = null;//OTA文件路径
    byte[] ReadData = null;//OTA文件字节流
    private int SendPacketID = 0;//当前包序号
    private int SendPacketAllNum = 0;//总包数
    private int SendSectionID = 0;//当前段序号
    int CRC = 0;//完整文件的的crc
    int SECTION_CRC = 0;//当前段CRC

    final byte CMD_FW_ERASE = 0x16;
    final byte CMD_FW_WRITE = 0x17;
    final byte CMD_FW_UPGRADE = 0x18;
    final byte CMD_FW_UPGRADEV20 = 0x15;

    final byte ACTIONTYPE_CMD_FW_WRITE_START = 0x01;
    final byte ACTIONTYPE_CMD_FW_WRITE_END = 0x02;
    final byte ACTIONTYPE_CMD_FW_ERASE = 0x03;
    final byte ACTIONTYPE_CMD_FW_WRITE = 0x04;
    final byte ACTIONTYPE_CMD_FW_UPGRADE = 0x05;
    final byte ACTIONTYPE_CMD_FW_FINISH = 0x09;

    final byte CMD_FW_WRITE_START = 0x14;

    private byte nowStep = 0;
    private int tryCount = 0;

    //MTM
    //    final String UUID_SERVER = "000000ff-0000-1000-8000-00805f9b34fb";
    //bat
    final String UUID_SERVER = "0000ff00-0000-1000-8000-00805f9b34fb";
    final String UUID_WRITE = "0000ff01-0000-1000-8000-00805f9b34fb";

    public static final String UART_SERVICE_UUID = "00000001-0000-1000-8000-00805f9b34fb"; // The UUID for service "0001"
    public static final String UART_CHARACTERISTIC_READ_UUID = "00000002-0000-1000-8000-00805f9b34fb"; // The UUID for service "0002"
    public static final String UART_CHARACTERISTIC_NOTIFY_UUID = "00000003-0000-1000-8000-00805f9b34fb"; // The UUID for service "0003"
    private static final String TAG = "testcrc";
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_ota);
        etLog = findViewById(R.id.et_log);
        XXPermissions.with(this)
                // 可设置被拒绝后继续申请，直到用户授权或者永久拒绝
                //.constantRequest()
                // 支持请求6.0悬浮窗权限8.0请求安装权限
                //.permission(Permission.SYSTEM_ALERT_WINDOW, Permission.REQUEST_INSTALL_PACKAGES)
                // 不指定权限则自动获取清单中的危险权限
                //.permission(Permission.Group.STORAGE, Permission.Group.CALENDAR)
                .request(new OnPermission() {

                    @Override
                    public void hasPermission(List<String> granted, boolean all) {
                        //启用蓝牙
                        BleManager.getInstance().enableBluetooth();
                        //初始化列表
                        initListView();
                        //扫描蓝牙
                        scanBle();
                    }

                    @Override
                    public void noPermission(List<String> denied, boolean quick) {

                    }
                });

        byte[] files = new byte[]{0x11,0x12,0x13,0x65};//CRC 155
        int fileCrc = 0;
        for (int i = 0; i < files.length; i++) {
            int CC = files[i];
            CC &= 0x000000FF;
            fileCrc += CC;
            fileCrc = fileCrc & 0x0000FFFF;
        }
        Log.d(TAG, "onCreate: "+fileCrc);
    }

    private void scanBle() {
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                addLog("搜索完成...");
                for (BleDevice bleDevice : scanResultList) {
                    if (!TextUtils.isEmpty(bleDevice.getName()) && (bleDevice.getName().startsWith("BAT001") || bleDevice.getName().startsWith("mtm"))) {
                        Map<String, String> listem = new HashMap<String, String>();
                        listem.put("name", bleDevice.getName());
                        listem.put("mac", bleDevice.getMac());
                        deviceList.add(listem);
                        resultBle.add(bleDevice);
                    }

                }
                myBleDeviceAdapter.notifyDataSetChanged();

            }

            @Override
            public void onScanStarted(boolean success) {
                addLog("扫描中...");
                deviceList.clear();
                resultBle.clear();

            }

            @Override
            public void onScanning(BleDevice bleDevice) {

            }
        });
    }

    private void initListView() {
        listView = (ListView) findViewById(R.id.listView);
        resultBle = new ArrayList<>();
        myBleDeviceAdapter = new SimpleAdapter(V30TestActivity.this,
                deviceList,
                android.R.layout.simple_list_item_2,
                new String[]{"name", "mac"},
                new int[]{android.R.id.text1, android.R.id.text2});
        listView.setAdapter(myBleDeviceAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                final BleDevice bleDevice = resultBle.get(i);
                BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
                    @Override
                    public void onStartConnect() {
                        addLog("开始连接" + bleDevice.getName());

                    }

                    @Override
                    public void onConnectFail(BleDevice bleDevice, BleException exception) {
                        addLog("连接失败" + bleDevice.getName());
                    }

                    @Override
                    public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                        addLog("连接成功" + bleDevice.getName());
                    }

                    @Override
                    public void onDisConnected(boolean isActiveDisConnected, BleDevice device, BluetoothGatt gatt, int status) {
                        addLog("断开连接" + bleDevice.getName());
                    }
                });

            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        BleManager.getInstance().disconnectAllDevice();
    }

    public void addLog(String text) {
        etLog.append(text);
        etLog.append("\n");
        etLog.setSelection(etLog.getText().length());
    }

    public void scanBle(View view) {
        scanBle();
    }

    public void startOta(View view) {
        if (BleManager.getInstance().getAllConnectedDevice() == null
                || BleManager.getInstance().getAllConnectedDevice().size() == 0) {
            addLog("请先点击连接蓝牙设备");
            return;
        }
        readFromFile();

    }

    private void readFromFile() {
        addLog("请稍等，擦除空间中！");
        listView.setEnabled(false);
        //1.读取文件中的字节数组
        OTA_FilePath = "/sdcard/update.bin";
        ReadData = ReadOTAFileBinary(OTA_FilePath);
        SendPacketAllNum = ReadData.length / MAX_TRANS_COUNT_V30;
        if (ReadData.length % MAX_TRANS_COUNT_V30 != 0)
            SendPacketAllNum += 1;
        addLog("总包数" + SendPacketAllNum + " 文件字节数" + ReadData.length);

        //2.计算当前文件的CRC
        for (int i = 0; i < ReadData.length; i++) {
            int CC = ReadData[i];
            CC &= 0x000000FF;
            CRC += CC;
            CRC = CRC & 0x0000FFFF;
        }
        addLog("计算得出文件CRC" + CRC);

        //3.计算总段数
        MAX_TRANS_COUNT = SendPacketAllNum / MAX_TRANS_SECTIONALL_PACKET_COUNT;
        if (SendPacketAllNum % MAX_TRANS_SECTIONALL_PACKET_COUNT != 0)
            MAX_TRANS_COUNT += 1;
        addLog("计算得出总段数" + MAX_TRANS_COUNT);

        //4.开始擦除
        byte[] erase = new byte[2];
        erase[0] = CMD_FW_ERASE;
        erase[1] = 0x00;
        writeData(erase);
        nowStep = ACTIONTYPE_CMD_FW_ERASE;


    }

    public void writeData(byte[] data) {
        BleManager.getInstance().write(BleManager.getInstance().getAllConnectedDevice().get(0),
                UUID_SERVER, UUID_WRITE, data, new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(int current, int total, byte[] justWrite) {
                        //addLog("写入数据成功");
                        if (nowStep == ACTIONTYPE_CMD_FW_ERASE) {
                            etLog.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    readData();
                                }
                            }, 3000);
                        } else if (nowStep == ACTIONTYPE_CMD_FW_WRITE_START) {
                            //addLog("写入片段" + SendSectionID);
                            OTA_Write_Section_All_Flash();
                        } else if (nowStep == ACTIONTYPE_CMD_FW_WRITE_END) {
                            addLog("完成片段传输" + SendSectionID);
                            readData();

                        } else if (nowStep == ACTIONTYPE_CMD_FW_UPGRADE) {
                            OTA_Upgrade_Flash_V30(ReadData.length, CRC);
                        } else if (nowStep == ACTIONTYPE_CMD_FW_FINISH) {
                            addLog("断开蓝牙");
                            BleManager.getInstance().disconnectAllDevice();
                        }
                    }

                    @Override
                    public void onWriteFailure(BleException exception) {
                        addLog("写入数据失败");
                    }
                });
    }

    public void readData() {
        BleManager.getInstance().read(BleManager.getInstance().getAllConnectedDevice().get(0),
                UUID_SERVER, UUID_WRITE, new BleReadCallback() {
                    @Override
                    public void onReadSuccess(byte[] data) {
                        addLog("读取擦写结果成功:" + ConvertUtils.bytes2HexString(data));
                        //当前处于擦写
                        if (nowStep == ACTIONTYPE_CMD_FW_ERASE) {
                            SendPacketID = 0;
                            writeFileData(data);
                        } else if (nowStep == ACTIONTYPE_CMD_FW_WRITE_END) {
                            //写入新片段
                            writeFileData(data);
                        }
                    }

                    @Override
                    public void onReadFailure(BleException exception) {

                    }
                });
    }

    //WEN 结束发包 发送八个字节结束包
    public void OTA_Upgrade_Flash_V30(int Size, int CRC) {
        Log.i("SYD_OTA", "OTA_Upgrade_Flash CRC_V30:" + CRC + "Size" + Size);
        byte[] WriteData = new byte[8];
        WriteData[0] = CMD_FW_UPGRADEV20;
        WriteData[1] = 0x04;
        WriteData[2] = (byte) (Size & 0x000000FF);
        WriteData[3] = (byte) ((Size & 0x0000FF00) >> 8);
        WriteData[4] = (byte) ((Size & 0x00FF0000) >> 16);
        WriteData[5] = (byte) ((Size & 0xFF000000) >> 24);
        WriteData[6] = (byte) (CRC & 0x000000FF);
        WriteData[7] = (byte) ((CRC & 0x0000FF00) >> 8);
        nowStep = ACTIONTYPE_CMD_FW_FINISH;
        writeData(WriteData);
        addLog("发送完成开始升级 CRC" + CRC);
    }

    private void writeFileData(byte[] data) {
        nowStep = ACTIONTYPE_CMD_FW_WRITE_START;
        //检验CRC是否正确
        if ((SendSectionID != 0) && (data != null)) {
            int check = ((data[7] & 0xff) << 8) | (data[6] & 0xff);

            //error check and resend
            if ((check & 0x0000ffff) != (SECTION_CRC & 0x0000ffff)) {
                SendSectionID -= 1;
                SendPacketID = MAX_TRANS_SECTIONALL_PACKET_COUNT * SendSectionID;
                String tip = "重发包段" + SendSectionID + "设备计算出的CRC" + check + "APP计算出的CRC" + SECTION_CRC;
                addLog(tip);
                Toast.makeText(V30TestActivity.this, tip, Toast.LENGTH_SHORT).show();
                tryCount++;
            }
            if (tryCount > 3) {
                addLog("失败次数大于3请重试");
                return;
            }
        }
        //开始计算段CRC
        if ((SendPacketAllNum - SendPacketID) > MAX_TRANS_SECTIONALL_PACKET_COUNT)
            MAX_TRANS_SECTIONALL_SIZE = MAX_TRANS_SECTIONALL_COUNT;
        else
            MAX_TRANS_SECTIONALL_SIZE = ReadData.length % MAX_TRANS_SECTIONALL_COUNT;

        SECTION_CRC = 0;

        for (int i = 0; i < MAX_TRANS_SECTIONALL_SIZE; i++) {
            int CC = ReadData[SendSectionID * MAX_TRANS_SECTIONALL_COUNT + i];
            CC &= 0x000000FF;
            SECTION_CRC += CC;
        }
        //写入段头数据
        OTA_Write_Flash_section_start(SECTION_CRC, MAX_TRANS_SECTIONALL_SIZE, SendSectionID);
        SendSectionID += 1;

    }

    //写入包数据
    public void OTA_Write_Section_All_Flash() {
        int srcPos = SendPacketID * MAX_TRANS_COUNT_V30;
        final byte[] dataPacket = new byte[MAX_TRANS_COUNT_V30];

        Log.i("SYD_OTA", "SendPacketID ==>" + SendPacketID);
        Log.i("SYD_OTA", "MAX_TRANS_COUNT_V30 ==>" + MAX_TRANS_COUNT_V30);
        Log.i("SYD_OTA", "srcPos ==>" + srcPos);
        Log.i("SYD_OTA", "SendPacketAllNum ==>" + SendPacketAllNum);

        if (SendPacketID == SendPacketAllNum) {
            nowStep = 0;
        } else {
            if (SendPacketID == (SendPacketAllNum - 1)) {
                //最后一包直接拷贝到数组中
                System.arraycopy(ReadData, srcPos, dataPacket, 0, (ReadData.length - srcPos));//last a packet
                //标志准备更新 ACTIONTYPE_CMD_FW_UPGRADE
                nowStep = ACTIONTYPE_CMD_FW_UPGRADE;//发送完最后一包了
            } else {
                //顺序读取20个字节
                System.arraycopy(ReadData, srcPos, dataPacket, 0, MAX_TRANS_COUNT_V30);//other packet except first and last packet
            }
            //组装这20字节传输
            writeData(dataPacket);
            //包序号+1准备下一包
            SendPacketID += 1;
        }
        if (nowStep != ACTIONTYPE_CMD_FW_UPGRADE) {
            if (SendPacketID % MAX_TRANS_SECTIONALL_PACKET_COUNT == 0) {
                nowStep = ACTIONTYPE_CMD_FW_WRITE_END;
                addLog("当前片段发送" + SendPacketID / MAX_TRANS_SECTIONALL_PACKET_COUNT);
            }
        }
        // 创建一个数值格式化对象
        NumberFormat numberFormat = NumberFormat.getInstance();
        // 设置精确到小数点后2位
        numberFormat.setMaximumFractionDigits(2);
        String result = numberFormat.format((float) SendPacketID / (float) SendPacketAllNum * 100) + "%";
        addLog("请勿中断，OTA进行中 ..." + result);


    }

    /*这里进行组包操作 写入第一包*/
    public void OTA_Write_Flash_section_start(int check, int size, int Address) {
        byte[] WriteData = new byte[10];
        Address = Address * MAX_TRANS_SECTIONALL_COUNT;

        WriteData[0] = CMD_FW_WRITE_START;
        WriteData[1] = 0x13;
        WriteData[2] = (byte) (Address & 0x000000FF);
        WriteData[3] = (byte) ((Address & 0x0000FF00) >> 8);
        WriteData[4] = (byte) ((Address & 0x00FF0000) >> 16);
        WriteData[5] = (byte) ((Address & 0xFF000000) >> 24);
        WriteData[6] = (byte) (size & 0x000000FF);
        WriteData[7] = (byte) ((size & 0x0000FF00) >> 8);
        WriteData[8] = (byte) (check & 0x000000FF);
        WriteData[9] = (byte) ((check & 0x0000FF00) >> 8);
        writeData(WriteData);//写入端头数据

    }

    byte[] ReadOTAFileBinary(String filepath) {
        File file = new File(filepath);
        try {
            FileInputStream fis = new FileInputStream(file);
            int length = fis.available();
            byte[] BinaryData = new byte[length];

            fis.read(BinaryData);

            fis.close();
            return BinaryData;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        byte[] BinaryData = new byte[]{0x01, 0x01};
        return BinaryData;
    }

    public void clearLog(View view) {
        etLog.setText("");
    }

    public void disconnectAll(View view) {
        clearLog(null);
        listView.setEnabled(true);
        BleManager.getInstance().disconnectAllDevice();
    }

    public void readPlugData(View view) {
        if (BleManager.getInstance().getAllConnectedDevice() == null
                || BleManager.getInstance().getAllConnectedDevice().size() == 0) {
            addLog("请先点击连接蓝牙设备");
            return;
        }
        BleManager.getInstance().notify(BleManager.getInstance().getAllConnectedDevice().get(0),
                UART_SERVICE_UUID, UART_CHARACTERISTIC_NOTIFY_UUID, new BleNotifyCallback() {
                    @Override
                    public void onNotifySuccess() {

                    }

                    @Override
                    public void onNotifyFailure(BleException exception) {
                        addLog("订阅通知失败:" + exception);
                    }

                    @Override
                    public void onCharacteristicChanged(byte[] data) {
                        addLog("收到通知:" + new String(data));

                    }
                });

    }

    public void read(View view) {
        if (BleManager.getInstance().getAllConnectedDevice() == null
                || BleManager.getInstance().getAllConnectedDevice().size() == 0) {
            addLog("请先点击连接蓝牙设备");
            return;
        }
        BleManager.getInstance().read(BleManager.getInstance().getAllConnectedDevice().get(0),
                UART_SERVICE_UUID, UART_CHARACTERISTIC_READ_UUID, new BleReadCallback() {
                    @Override
                    public void onReadSuccess(byte[] data) {
                        addLog("读取成功:" + new String(data));
                    }

                    @Override
                    public void onReadFailure(BleException exception) {
                        addLog("读取失败:" + exception);
                    }
                });
    }

    int value = 1;
    public void clickOn(View view) {
        value = value == 1 ? 0 : 1;
        String cmd = "D6_X8_togle:" + value;
        BleManager.getInstance().write(BleManager.getInstance().getAllConnectedDevice().get(0),
                UART_SERVICE_UUID, UART_CHARACTERISTIC_READ_UUID, cmd.getBytes(), new BleWriteCallback() {
                    @Override
                    public void onWriteSuccess(int current, int total, byte[] justWrite) {
                       addLog("操作成功");
                    }

                    @Override
                    public void onWriteFailure(BleException exception) {
                        addLog("操作失败");
                    }
                });
        addLog(cmd);
    }
}
